<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="mobile-web-app-capable" content="yes">
    <title>3D跳一跳</title>
    <style>
        body {
            margin: 0;
            overflow: hidden;
            font-family: 'Arial', sans-serif;
            touch-action: none;
            background-color: #f8f8f8;
        }
        #gameCanvas {
            display: block;
            width: 100%;
            height: 100vh;
        }
        #score {
            position: absolute;
            top: 20px;
            left: 20px;
            font-size: 24px;
            color: #333;
            text-shadow: 1px 1px 2px rgba(255, 255, 255, 0.8);
            font-weight: bold;
            background-color: rgba(255, 255, 255, 0.6);
            padding: 5px 10px;
            border-radius: 10px;
        }
        #highScore {
            position: absolute;
            top: 60px;
            left: 20px;
            font-size: 18px;
            color: #333;
            text-shadow: 1px 1px 2px rgba(255, 255, 255, 0.8);
            font-weight: bold;
            background-color: rgba(255, 255, 255, 0.6);
            padding: 5px 10px;
            border-radius: 10px;
        }
        #timer {
            position: absolute;
            top: 100px;
            left: 20px;
            font-size: 18px;
            color: #e74c3c;
            text-shadow: 1px 1px 2px rgba(255, 255, 255, 0.8);
            font-weight: bold;
            background-color: rgba(255, 255, 255, 0.6);
            padding: 5px 10px;
            border-radius: 10px;
        }
        #gameOver {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            background-color: rgba(255, 255, 255, 0.9);
            color: #333;
            padding: 30px 40px;
            border-radius: 15px;
            text-align: center;
            display: none;
            box-shadow: 0 8px 30px rgba(0, 0, 0, 0.3);
        }
        #gameOver h2 {
            margin-top: 0;
            color: #e74c3c;
            font-size: 32px;
        }
        #finalScore, #finalHighScore {
            font-size: 24px;
            margin: 10px 0;
        }
        #restartBtn, #backToMainBtn {
            margin: 10px;
            padding: 15px 30px;
            background-color: #07c160;
            color: white;
            border: none;
            border-radius: 30px;
            cursor: pointer;
            font-size: 18px;
            box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
            transition: all 0.2s;
            -webkit-tap-highlight-color: transparent;
        }
        #backToMainBtn {
            background-color: #3498db;
        }
        #restartBtn:hover, #backToMainBtn:hover {
            transform: translateY(-2px);
            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
        }
        #restartBtn:hover {
            background-color: #06ad56;
        }
        #backToMainBtn:hover {
            background-color: #2980b9;
        }
        #startScreen {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            background-color: rgba(255, 255, 255, 0.9);
            color: #333;
            padding: 30px 40px;
            border-radius: 15px;
            text-align: center;
            box-shadow: 0 8px 30px rgba(0, 0, 0, 0.3);
            max-width: 90%;
            width: 400px;
        }
        #startScreen h2 {
            font-size: 36px;
            margin-top: 0;
            color: #2c3e50;
            text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.1);
        }
        #startScreen p {
            margin: 10px 0;
            font-size: 18px;
            color: #555;
        }
        .mode-selection {
            display: flex;
            justify-content: center;
            margin: 20px 0;
            gap: 10px;
        }
        .mode-btn {
            padding: 10px 20px;
            background-color: #ecf0f1;
            color: #333;
            border: 2px solid #bdc3c7;
            border-radius: 20px;
            cursor: pointer;
            font-size: 16px;
            transition: all 0.2s;
        }
        .mode-btn.active {
            background-color: #3498db;
            color: white;
            border-color: #2980b9;
        }
        #startBtn {
            margin-top: 20px;
            padding: 15px 40px;
            background-color: #07c160;
            color: white;
            border: none;
            border-radius: 30px;
            cursor: pointer;
            font-size: 20px;
            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
            transition: all 0.2s;
            -webkit-tap-highlight-color: transparent;
            width: 80%;
        }
        #startBtn:hover {
            background-color: #06ad56;
            transform: translateY(-2px);
            box-shadow: 0 6px 16px rgba(0, 0, 0, 0.3);
        }
        .power-bar-container {
            position: absolute;
            bottom: 50px;
            left: 50%;
            transform: translateX(-50%);
            width: 60%;
            max-width: 300px;
            height: 15px;
            background-color: rgba(255, 255, 255, 0.5);
            border-radius: 8px;
            display: none;
            overflow: hidden;
            box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
        }
        .power-bar {
            height: 100%;
            width: 0%;
            background-color: #ff4500;
            border-radius: 5px;
            transition: width 0.05s linear;
        }
        .shadow-player {
            position: absolute;
            width: 50px;
            height: 50px;
            border-radius: 50%;
            background-color: rgba(0, 0, 0, 0.2);
            pointer-events: none;
            transform: translateX(-50%);
            display: none;
        }
        .audio-control {
            position: absolute;
            top: 20px;
            right: 20px;
            width: 40px;
            height: 40px;
            background-color: rgba(255, 255, 255, 0.7);
            border-radius: 50%;
            display: flex;
            justify-content: center;
            align-items: center;
            cursor: pointer;
            box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
            z-index: 100;
            transition: all 0.2s;
        }
        .audio-control:hover {
            background-color: rgba(255, 255, 255, 0.9);
            transform: scale(1.1);
        }
        .audio-control svg {
            width: 24px;
            height: 24px;
            fill: #333;
        }
        .target-indicator {
            position: absolute;
            width: 40px;
            height: 40px;
            pointer-events: none;
            z-index: 10;
            animation: pulse 1.5s infinite;
        }
        
        @keyframes pulse {
            0% { transform: scale(1) translate(-50%, -50%); opacity: 0.7; }
            50% { transform: scale(1.2) translate(-42%, -42%); opacity: 1; }
            100% { transform: scale(1) translate(-50%, -50%); opacity: 0.7; }
        }
        
        .target-arrow {
            position: absolute;
            width: 30px;
            height: 30px;
            top: 50%; 
            left: 50%;
            transform: translate(-50%, -50%);
            opacity: 0.8;
            pointer-events: none;
            z-index: 10;
        }
    </style>
</head>
<body>
    <canvas id="gameCanvas"></canvas>
    <div id="score">分数: 0</div>
    <div id="highScore">最高分: 0</div>
    <div id="timer" style="display: none;">时间: 60</div>
    <div id="gameOver">
        <h2>游戏结束!</h2>
        <div id="finalScore">分数: 0</div>
        <div id="finalHighScore">最高分: 0</div>
        <button id="restartBtn">再来一次</button>
        <button id="backToMainBtn">返回主菜单</button>
    </div>
    <div id="startScreen">
        <h2>3D跳一跳</h2>
        <p>按住屏幕或鼠标蓄力，松开跳跃</p>
        <p>跳到方块中心得分更高</p>
        <div class="mode-selection">
            <button id="normalModeBtn" class="mode-btn active">普通模式</button>
            <button id="timeModeBtn" class="mode-btn">限时模式</button>
        </div>
        <button id="startBtn">开始游戏</button>
    </div>
    <div class="power-bar-container">
        <div class="power-bar"></div>
    </div>
    <div class="shadow-player"></div>
    <div class="audio-control" id="audioControl">
        <svg viewBox="0 0 24 24" id="audioIcon">
            <path d="M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z"/>
        </svg>
    </div>
    <div class="target-indicator" id="targetIndicator" style="display: none;">
        <svg viewBox="0 0 24 24" fill="#e74c3c">
            <path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z"/>
            <circle cx="12" cy="12" r="5" fill="#e74c3c"/>
        </svg>
    </div>
    <div class="target-arrow" id="targetArrow" style="display: none;">
        <svg viewBox="0 0 24 24" fill="#e74c3c">
            <path d="M12 4l-1.41 1.41L16.17 11H4v2h12.17l-5.58 5.59L12 20l8-8z"/>
        </svg>
    </div>

    <audio id="bgMusic" loop>
        <source src="https://cdn.freesound.org/previews/353/353546_5396137-lq.mp3" type="audio/mpeg">
    </audio>
    <audio id="jumpSound">
        <source src="https://cdn.freesound.org/previews/369/369515_6687700-lq.mp3" type="audio/mpeg">
    </audio>
    <audio id="landSound">
        <source src="https://cdn.freesound.org/previews/397/397701_4284968-lq.mp3" type="audio/mpeg">
    </audio>
    <audio id="gameOverSound">
        <source src="https://cdn.freesound.org/previews/277/277021_5379050-lq.mp3" type="audio/mpeg">
    </audio>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
    <script>
        // 全局变量
        let camera, scene, renderer, player, platforms = [], shadows = [];
        let score = 0, gameStarted = false, gameOver = false;
        let jumping = false, jumpPower = 0, jumpStart = 0;
        let currentPlatform = 0, targetPlatform = 1;
        let jumpDirection = new THREE.Vector3();
        let clock = new THREE.Clock();
        let playerShadow, pointLight;
        let animationFrameId = null;
        let soundEnabled = true;
        let particles = [];
        let highScore = 0;
        let gameMode = 'normal'; // 'normal', 'time', 'challenge'
        let timeRemaining = 60; // 秒
        let timerInterval = null;
        let canCancelJump = true; // 是否允许取消蓄力
        
        const platformColors = [
            0x8ecdf8, 0xffbe76, 0xff7979, 0xbadc58, 0x7ed6df, 0xe056fd, 0x686de0
        ];
        
        const platformShapes = ['cube', 'cube', 'cube', 'cylinder', 'cube'];
        
        // DOM元素
        const scoreElement = document.getElementById('score');
        const highScoreElement = document.getElementById('highScore');
        const gameOverElement = document.getElementById('gameOver');
        const finalScoreElement = document.getElementById('finalScore');
        const finalHighScoreElement = document.getElementById('finalHighScore');
        const restartBtn = document.getElementById('restartBtn');
        const backToMainBtn = document.getElementById('backToMainBtn');
        const startScreen = document.getElementById('startScreen');
        const startBtn = document.getElementById('startBtn');
        const normalModeBtn = document.getElementById('normalModeBtn');
        const timeModeBtn = document.getElementById('timeModeBtn');
        const powerBarContainer = document.querySelector('.power-bar-container');
        const powerBar = document.querySelector('.power-bar');
        const shadowPlayer = document.querySelector('.shadow-player');
        const timerElement = document.getElementById('timer');
        const targetIndicator = document.getElementById('targetIndicator');
        const targetArrow = document.getElementById('targetArrow');
        
        // 音频控制
        const bgMusic = document.getElementById('bgMusic');
        const jumpSound = document.getElementById('jumpSound');
        const landSound = document.getElementById('landSound');
        const gameOverSound = document.getElementById('gameOverSound');
        const audioControl = document.getElementById('audioControl');
        const audioIcon = document.getElementById('audioIcon');
        
        // 载入高分记录
        function loadHighScore() {
            const savedScore = localStorage.getItem('jumpHighScore');
            if (savedScore) {
                highScore = parseInt(savedScore);
                highScoreElement.textContent = `最高分: ${highScore}`;
            }
        }
        
        // 保存高分记录
        function saveHighScore() {
            if (score > highScore) {
                highScore = score;
                localStorage.setItem('jumpHighScore', highScore);
                highScoreElement.textContent = `最高分: ${highScore}`;
            }
        }
        
        // 创建粒子效果
        function createParticles(position, color, count = 20) {
            for (let i = 0; i < count; i++) {
                const geometry = new THREE.SphereGeometry(0.1, 6, 6);
                const material = new THREE.MeshBasicMaterial({
                    color: color,
                    transparent: true,
                    opacity: 0.8
                });
                
                const particle = new THREE.Mesh(geometry, material);
                particle.position.copy(position);
                
                // 随机速度
                particle.velocity = new THREE.Vector3(
                    (Math.random() - 0.5) * 2,
                    Math.random() * 2 + 1,
                    (Math.random() - 0.5) * 2
                );
                
                particle.lifetime = 0;
                particle.maxLifetime = 1 + Math.random();
                
                scene.add(particle);
                particles.push(particle);
            }
        }
        
        // 更新粒子效果
        function updateParticles(deltaTime) {
            const particlesToRemove = [];
            
            for (let i = 0; i < particles.length; i++) {
                const particle = particles[i];
                
                // 更新位置
                particle.position.x += particle.velocity.x * deltaTime;
                particle.position.y += particle.velocity.y * deltaTime;
                particle.position.z += particle.velocity.z * deltaTime;
                
                // 添加重力
                particle.velocity.y -= 5 * deltaTime;
                
                // 减小不透明度
                particle.material.opacity = 1 - (particle.lifetime / particle.maxLifetime);
                
                // 更新生命周期
                particle.lifetime += deltaTime;
                
                // 检查是否应该移除
                if (particle.lifetime >= particle.maxLifetime) {
                    particlesToRemove.push(particle);
                }
            }
            
            // 移除过期粒子
            for (const particle of particlesToRemove) {
                scene.remove(particle);
                particles.splice(particles.indexOf(particle), 1);
            }
        }
        
        // 设置游戏模式
        function setGameMode(mode) {
            gameMode = mode;
            
            if (mode === 'time') {
                timeRemaining = 60;
                timerElement.textContent = `时间: ${timeRemaining}`;
                timerElement.style.display = 'block';
                
                // 启动计时器
                if (timerInterval) clearInterval(timerInterval);
                timerInterval = setInterval(() => {
                    timeRemaining--;
                    timerElement.textContent = `时间: ${timeRemaining}`;
                    
                    if (timeRemaining <= 0) {
                        // 游戏结束
                        clearInterval(timerInterval);
                        onFailedLanding();
                    }
                }, 1000);
            } else {
                timerElement.style.display = 'none';
                if (timerInterval) {
                    clearInterval(timerInterval);
                    timerInterval = null;
                }
            }
        }
        
        // 初始化游戏
        function init() {
            // 创建场景
            scene = new THREE.Scene();
            scene.background = new THREE.Color(0xc7ecee);
            scene.fog = new THREE.Fog(0xc7ecee, 10, 50);
            
            // 创建相机
            camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 1000);
            camera.position.set(0, 10, 15);
            camera.lookAt(0, 0, 0);
            
            // 创建渲染器
            renderer = new THREE.WebGLRenderer({ 
                canvas: document.getElementById('gameCanvas'),
                antialias: true 
            });
            renderer.setSize(window.innerWidth, window.innerHeight);
            renderer.shadowMap.enabled = true;
            
            // 添加光源
            const ambientLight = new THREE.AmbientLight(0xffffff, 0.6);
            scene.add(ambientLight);
            
            pointLight = new THREE.PointLight(0xffffff, 1);
            pointLight.position.set(10, 15, 10);
            pointLight.castShadow = true;
            pointLight.shadow.mapSize.width = 2048;
            pointLight.shadow.mapSize.height = 2048;
            scene.add(pointLight);

            const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
            directionalLight.position.set(5, 10, 7.5);
            directionalLight.castShadow = true;
            scene.add(directionalLight);
            
            // 重置游戏状态
            score = 0;
            gameOver = false;
            platforms = [];
            shadows = [];
            particles = [];
            currentPlatform = 0;
            targetPlatform = 1;
            
            // 清除场景
            while(scene.children.length > 0){ 
                scene.remove(scene.children[0]); 
            }
            scene.add(ambientLight);
            scene.add(pointLight);
            scene.add(directionalLight);
            
            // 创建玩家
            createPlayer();
            
            // 创建初始平台
            createPlatform(0, 0, 0, 'cube', 0x8ecdf8);
            createPlatform(4, 0, 0, getRandomShape(), getRandomColor());
            
            // 更新分数显示
            scoreElement.textContent = `分数: ${score}`;
            
            // 设置相机位置
            updateCamera();
            
            // 设置游戏模式
            if (gameMode === 'time') {
                setGameMode('time');
            }
        }
        
        // 创建玩家
        function createPlayer() {
            const geometry = new THREE.SphereGeometry(0.5, 32, 32);
            const material = new THREE.MeshLambertMaterial({ color: 0x333333 });
            player = new THREE.Mesh(geometry, material);
            player.position.set(0, 1, 0);
            player.castShadow = true;
            player.receiveShadow = false;
            scene.add(player);
            
            // 创建跳跃阴影预测
            const shadowGeometry = new THREE.CircleGeometry(0.5, 32);
            const shadowMaterial = new THREE.MeshBasicMaterial({ 
                color: 0x000000, 
                transparent: true,
                opacity: 0.2
            });
            playerShadow = new THREE.Mesh(shadowGeometry, shadowMaterial);
            playerShadow.rotation.x = -Math.PI / 2;
            playerShadow.position.y = 0.01;
            playerShadow.visible = false;
            scene.add(playerShadow);
        }
        
        // 获取随机颜色
        function getRandomColor() {
            return platformColors[Math.floor(Math.random() * platformColors.length)];
        }
        
        // 获取随机形状
        function getRandomShape() {
            return platformShapes[Math.floor(Math.random() * platformShapes.length)];
        }
        
        // 创建平台
        function createPlatform(x, y, z, shape = 'cube', color = 0x8ecdf8) {
            let geometry, platformWidth, platformDepth;
            
            platformWidth = 2 + Math.random() * 1; // 宽度随机 2-3
            platformDepth = 2 + Math.random() * 1; // 深度随机 2-3
            
            if (shape === 'cube') {
                geometry = new THREE.BoxGeometry(platformWidth, 1, platformDepth);
            } else if (shape === 'cylinder') {
                const radius = platformWidth / 2;
                geometry = new THREE.CylinderGeometry(radius, radius, 1, 32);
                platformDepth = platformWidth; // 对于圆柱体，宽度=深度=直径
            }
            
            const material = new THREE.MeshLambertMaterial({ color: color });
            const platform = new THREE.Mesh(geometry, material);
            platform.position.set(x, y, z);
            platform.receiveShadow = true;
            platform.castShadow = true;
            
            // 存储平台信息
            const platformInfo = {
                mesh: platform,
                shape: shape,
                width: platformWidth,
                depth: platformDepth,
                position: new THREE.Vector3(x, y, z)
            };
            
            platforms.push(platformInfo);
            scene.add(platform);
            
            // 创建平台阴影
            const shadowGeometry = new THREE.PlaneGeometry(platformWidth + 0.1, platformDepth + 0.1);
            const shadowMaterial = new THREE.MeshBasicMaterial({ 
                color: 0x000000, 
                transparent: true,
                opacity: 0.2
            });
            const shadow = new THREE.Mesh(shadowGeometry, shadowMaterial);
            shadow.rotation.x = -Math.PI / 2;
            shadow.position.set(x, -0.49, z);
            shadows.push(shadow);
            scene.add(shadow);
            
            return platformInfo;
        }
        
        // 生成下一个平台
        function createNextPlatform() {
            const lastPlatform = platforms[platforms.length - 1];
            const minDistance = 4; // 增加最小距离
            const maxDistance = 7; // 增加最大距离
            
            let attempts = 0;
            const maxAttempts = 10;
            let newPlatform = null;
            
            // 尝试生成不重叠的平台
            while (attempts < maxAttempts && !newPlatform) {
                // 计算随机距离和角度
                const distance = minDistance + Math.random() * (maxDistance - minDistance);
                const angle = Math.random() * Math.PI * 2; // 随机方向
                
                const x = lastPlatform.position.x + Math.cos(angle) * distance;
                const z = lastPlatform.position.z + Math.sin(angle) * distance;
                
                // 检查是否与现有平台重叠
                let overlapping = false;
                for (let i = 0; i < platforms.length; i++) {
                    const platform = platforms[i];
                    const dx = x - platform.position.x;
                    const dz = z - platform.position.z;
                    const minSeparation = 3; // 平台之间的最小间距
                    
                    if (Math.sqrt(dx * dx + dz * dz) < minSeparation) {
                        overlapping = true;
                        break;
                    }
                }
                
                if (!overlapping) {
                    // 创建新平台
                    newPlatform = createPlatform(x, 0, z, getRandomShape(), getRandomColor());
                }
                
                attempts++;
            }
            
            // 如果无法找到合适位置，则在最后一个平台远处创建
            if (!newPlatform) {
                const fallbackDistance = maxDistance + 1;
                const fallbackAngle = Math.random() * Math.PI * 2;
                const fallbackX = lastPlatform.position.x + Math.cos(fallbackAngle) * fallbackDistance;
                const fallbackZ = lastPlatform.position.z + Math.sin(fallbackAngle) * fallbackDistance;
                newPlatform = createPlatform(fallbackX, 0, fallbackZ, getRandomShape(), getRandomColor());
            }
            
            return newPlatform;
        }
        
        // 更新目标指示器
        function updateTargetIndicator() {
            if (!gameStarted || gameOver || jumping || player.jumping) {
                targetIndicator.style.display = 'none';
                targetArrow.style.display = 'none';
                return;
            }
            
            if (targetPlatform < platforms.length) {
                const targetPlatformObj = platforms[targetPlatform];
                
                // 将3D坐标转换为屏幕坐标
                const vector = new THREE.Vector3();
                vector.setFromMatrixPosition(targetPlatformObj.mesh.matrixWorld);
                vector.project(camera);
                
                const widthHalf = window.innerWidth / 2;
                const heightHalf = window.innerHeight / 2;
                
                const x = (vector.x * widthHalf) + widthHalf;
                const y = - (vector.y * heightHalf) + heightHalf;
                
                // 检查目标是否在视口内
                const isInViewport = (
                    x > 0 && x < window.innerWidth &&
                    y > 0 && y < window.innerHeight
                );
                
                if (isInViewport) {
                    // 显示目标指示器
                    targetIndicator.style.display = 'block';
                    targetIndicator.style.left = x + 'px';
                    targetIndicator.style.top = y + 'px';
                    targetArrow.style.display = 'none';
                } else {
                    // 显示箭头指向视口外的目标
                    targetIndicator.style.display = 'none';
                    targetArrow.style.display = 'block';
                    
                    // 计算箭头位置和角度
                    const centerX = window.innerWidth / 2;
                    const centerY = window.innerHeight / 2;
                    
                    // 计算从中心到目标的角度
                    const angle = Math.atan2(y - centerY, x - centerX);
                    
                    // 计算边缘坐标
                    const edgeDistance = Math.min(window.innerWidth, window.innerHeight) * 0.4;
                    const edgeX = centerX + Math.cos(angle) * edgeDistance;
                    const edgeY = centerY + Math.sin(angle) * edgeDistance;
                    
                    // 设置箭头位置
                    targetArrow.style.left = edgeX + 'px';
                    targetArrow.style.top = edgeY + 'px';
                    
                    // 设置箭头旋转
                    const degrees = (angle * 180 / Math.PI);
                    targetArrow.style.transform = `translate(-50%, -50%) rotate(${degrees}deg)`;
                }
            } else {
                targetIndicator.style.display = 'none';
                targetArrow.style.display = 'none';
            }
        }
        
        // 开始跳跃
        function startJump() {
            if (!player.jumping && !gameOver && gameStarted) {
                jumping = true;
                jumpStart = Date.now();
                powerBarContainer.style.display = 'block';
                jumpHelpText.style.display = 'block';
                
                // 确保targetPlatform索引有效
                if (targetPlatform >= platforms.length) {
                    targetPlatform = platforms.length - 1;
                }
                
                // 计算方向向量
                jumpDirection.subVectors(
                    platforms[targetPlatform].position, 
                    player.position
                ).normalize();
                jumpDirection.y = 0; // 确保Y轴分量为0
                
                // 显示预测阴影
                updateJumpPreview();
                
                // 隐藏目标指示器
                targetIndicator.style.display = 'none';
                targetArrow.style.display = 'none';
            }
        }
        
        // 取消跳跃
        function cancelJump() {
            if (jumping && canCancelJump) {
                jumping = false;
                powerBarContainer.style.display = 'none';
                playerShadow.visible = false;
                jumpHelpText.style.display = 'none';
                
                // 重新显示目标指示器
                updateTargetIndicator();
            }
        }
        
        // 更新跳跃预览
        function updateJumpPreview() {
            if (jumping) {
                const jumpDuration = (Date.now() - jumpStart) / 1000;
                const jumpForce = Math.min(jumpDuration * 7, 10);
                
                // 确保targetPlatform索引有效
                if (targetPlatform < platforms.length) {
                    const nextPlatformPos = platforms[targetPlatform].position;
                    
                    // 计算落点
                    const jumpVelocity = jumpDirection.clone().multiplyScalar(jumpForce * 1.2);
                    const jumpTime = 2 * jumpVelocity.length() / 10; // 预估跳跃时间
                    const landingX = player.position.x + jumpVelocity.x * jumpTime;
                    const landingZ = player.position.z + jumpVelocity.z * jumpTime;
                    
                    // 设置阴影位置
                    playerShadow.position.set(landingX, 0.01, landingZ);
                    playerShadow.visible = true;
                }
                
                // 更新力度条
                const powerPercentage = Math.min(jumpDuration * 50, 100);
                powerBar.style.width = powerPercentage + '%';
                
                // 颜色渐变
                if (powerPercentage < 40) {
                    powerBar.style.backgroundColor = '#4cd137';
                } else if (powerPercentage < 70) {
                    powerBar.style.backgroundColor = '#fbc531';
                } else {
                    powerBar.style.backgroundColor = '#e84118';
                }
                
                if (jumping) {
                    requestAnimationFrame(updateJumpPreview);
                }
            }
        }
        
        // 结束跳跃
        function endJump() {
            if (jumping && !gameOver) {
                jumping = false;
                powerBarContainer.style.display = 'none';
                playerShadow.visible = false;
                jumpHelpText.style.display = 'none';
                
                const jumpDuration = Math.min((Date.now() - jumpStart) / 1000, 1.5);
                const jumpForce = Math.min(jumpDuration * 7, 10); // 最大力度10
                
                // 播放跳跃音效
                playSound(jumpSound);
                
                // 计算跳跃速度
                const jumpVelocity = jumpDirection.clone().multiplyScalar(jumpForce * 1.2);
                
                // 设置动画参数
                player.jumping = true;
                player.jumpVelocity = jumpVelocity.clone();
                player.jumpStartPos = player.position.clone();
                player.jumpTime = 0;
                player.jumpHeight = jumpForce * 0.8; // 跳跃高度与力度成正比
            }
        }
        
        // 更新玩家跳跃动画
        function updatePlayerJump(deltaTime) {
            if (player.jumping) {
                player.jumpTime += deltaTime * 2;
                
                // 计算跳跃位置 - 使用抛物线
                const t = player.jumpTime;
                const jumpProgress = Math.min(t, 1); // 0到1之间
                
                // 水平移动
                player.position.x = player.jumpStartPos.x + player.jumpVelocity.x * t;
                player.position.z = player.jumpStartPos.z + player.jumpVelocity.z * t;
                
                // 垂直移动 - 抛物线
                player.position.y = player.jumpStartPos.y + player.jumpHeight * Math.sin(Math.PI * jumpProgress);
                
                // 旋转动画
                player.rotation.x = -Math.PI * 2 * jumpProgress;
                
                // 检查是否完成跳跃
                if (jumpProgress >= 1) {
                    player.jumping = false;
                    player.position.y = 1; // 重置高度
                    player.rotation.x = 0;
                    checkLanding();
                }
                
                // 检查是否掉落到很低的位置
                if (player.position.y < -10) {
                    player.jumping = false;
                    onFailedLanding();
                }
            }
        }
        
        // 检查着陆
        function checkLanding() {
            // 检查targetPlatform是否有效
            if (targetPlatform >= platforms.length) {
                // 如果索引无效，直接认为失败
                onFailedLanding();
                return;
            }
            
            const targetPlatformPos = platforms[targetPlatform].position;
            const targetPlatformObj = platforms[targetPlatform];
            
            // 计算水平距离
            const dx = player.position.x - targetPlatformPos.x;
            const dz = player.position.z - targetPlatformPos.z;
            const distance = Math.sqrt(dx * dx + dz * dz);
            
            let onPlatform = false;
            let accuracy = 0;
            
            if (targetPlatformObj.shape === 'cube') {
                // 对于方块，我们需要检查是否在边界内
                const halfWidth = targetPlatformObj.width / 2;
                const halfDepth = targetPlatformObj.depth / 2;
                
                if (Math.abs(dx) <= halfWidth && Math.abs(dz) <= halfDepth) {
                    // 成功着陆
                    onPlatform = true;
                    const centerDistance = distance / Math.sqrt(halfWidth * halfWidth + halfDepth * halfDepth);
                    accuracy = 1 - centerDistance;
                }
            } else if (targetPlatformObj.shape === 'cylinder') {
                // 对于圆柱体，检查是否在半径内
                const platformRadius = targetPlatformObj.width / 2;
                
                if (distance <= platformRadius) {
                    // 成功着陆
                    onPlatform = true;
                    const centerDistance = distance / platformRadius;
                    accuracy = 1 - centerDistance;
                }
            }
            
            if (onPlatform) {
                onSuccessfulLanding(accuracy);
            } else {
                onFailedLanding();
            }
        }
        
        // 成功着陆
        function onSuccessfulLanding(accuracy) {
            // 播放着陆音效
            playSound(landSound);
            
            // 设置新的当前平台
            currentPlatform = targetPlatform;
            targetPlatform = platforms.length; // 将指向下一个平台的索引
            
            // 计算得分 (基于精准度)
            const basePoints = 10;
            const bonusPoints = Math.round(20 * accuracy);
            const points = basePoints + bonusPoints;
            
            score += points;
            scoreElement.textContent = `分数: ${score}`;
            
            // 如果是时间模式，添加时间
            if (gameMode === 'time') {
                timeRemaining += 2; // 每次成功着陆增加2秒
                document.getElementById('timer').textContent = `时间: ${timeRemaining}`;
            }
            
            // 创建成功着陆的粒子效果
            createParticles(
                new THREE.Vector3(player.position.x, 0.5, player.position.z),
                platforms[currentPlatform].mesh.material.color.getHex(),
                10
            );
            
            // 闪烁平台颜色表示成功
            const originalColor = platforms[currentPlatform].mesh.material.color.getHex();
            platforms[currentPlatform].mesh.material.color.setHex(0x44bd32);
            
            setTimeout(() => {
                if (!gameOver && currentPlatform < platforms.length) {
                    platforms[currentPlatform].mesh.material.color.setHex(originalColor);
                }
            }, 200);
            
            // 创建新平台
            createNextPlatform();
            
            // 更新目标平台索引
            targetPlatform = platforms.length - 1;
            
            // 删除旧平台（保持最多5个平台）
            if (platforms.length > 5) {
                const oldPlatform = platforms.shift();
                scene.remove(oldPlatform.mesh);
                
                const oldShadow = shadows.shift();
                scene.remove(oldShadow);
                
                currentPlatform--;
                targetPlatform--;
            }
            
            // 更新相机
            updateCamera();
        }
        
        // 失败着陆
        function onFailedLanding() {
            // 播放游戏结束音效
            playSound(gameOverSound);
            
            // 创建失败粒子效果
            createParticles(
                new THREE.Vector3(player.position.x, player.position.y, player.position.z),
                0xff0000,
                30
            );
            
            // 玩家掉落动画
            player.falling = true;
            player.fallSpeed = 0;
            
            // 更新游戏状态
            gameOver = true;
            
            // 保存高分
            saveHighScore();
            
            // 清除计时器
            if (timerInterval) {
                clearInterval(timerInterval);
                timerInterval = null;
            }
            
            // 显示游戏结束界面
            setTimeout(() => {
                finalScoreElement.textContent = `最终分数: ${score}`;
                finalHighScoreElement.textContent = `最高分: ${highScore}`;
                gameOverElement.style.display = 'block';
            }, 1500);
        }
        
        // 更新相机位置
        function updateCamera() {
            if (currentPlatform < platforms.length) {
                // 计算目标相机位置
                const targetPos = platforms[currentPlatform].position.clone();
                
                // 设置相机偏移
                targetPos.y += 10; // 高度
                targetPos.x -= 2; // 横向偏移
                targetPos.z += 15; // 纵向偏移
                
                // 平滑移动相机
                camera.position.lerp(targetPos, 0.1);
                
                // 设置相机朝向
                camera.lookAt(
                    platforms[currentPlatform].position.x + 2,
                    platforms[currentPlatform].position.y,
                    platforms[currentPlatform].position.z - 2
                );
            }
        }
        
        // 动画循环
        function animate() {
            if (gameOver && player.position.y < -20) {
                // 如果游戏结束且玩家已经掉得很低，停止动画循环
                return;
            }
            
            animationFrameId = requestAnimationFrame(animate);
            
            const deltaTime = clock.getDelta();
            
            // 更新玩家动画
            if (player.jumping) {
                updatePlayerJump(deltaTime);
            }
            
            // 玩家掉落动画
            if (player.falling) {
                player.fallSpeed += 9.8 * deltaTime; // 重力加速度
                player.position.y -= player.fallSpeed * deltaTime;
                player.rotation.x += 5 * deltaTime;
                player.rotation.z += 3 * deltaTime;
                
                // 相机跟随掉落的玩家
                if (camera.position.y > 5) {
                    camera.position.y -= deltaTime * 2;
                }
            }
            
            // 更新粒子效果
            updateParticles(deltaTime);
            
            // 更新目标指示器
            updateTargetIndicator();
            
            // 平滑更新相机
            if (!gameOver && !player.jumping) {
                updateCamera();
            }
            
            // 更新光源位置
            pointLight.position.set(
                camera.position.x + 5,
                camera.position.y + 5,
                camera.position.z - 5
            );
            
            renderer.render(scene, camera);
        }
        
        // 停止动画循环
        function stopAnimation() {
            if (animationFrameId !== null) {
                cancelAnimationFrame(animationFrameId);
                animationFrameId = null;
            }
        }
        
        // 重新启动动画循环
        function restartAnimation() {
            if (animationFrameId === null) {
                animationFrameId = requestAnimationFrame(animate);
            }
        }
        
        // 初始化事件监听
        document.addEventListener('mousedown', startJump);
        document.addEventListener('mouseup', endJump);
        document.addEventListener('keydown', (e) => {
            // ESC键取消跳跃
            if (e.key === 'Escape') {
                cancelJump();
            }
        });

        // 处理多点触摸
        let touchStartCount = 0;
        document.addEventListener('touchstart', (e) => {
            touchStartCount = e.touches.length;
            
            // 只有在游戏已开始且不是点击按钮时才进行处理
            if (gameStarted && e.target.tagName !== 'BUTTON') {
                e.preventDefault();
                
                // 单指触摸开始蓄力，双指触摸取消蓄力
                if (touchStartCount === 1) {
                    startJump();
                } else if (touchStartCount >= 2) {
                    cancelJump();
                }
            }
        }, { passive: false });

        // 处理触摸结束
        document.addEventListener('touchend', (e) => {
            // 只有在游戏已开始且不是点击按钮时才进行处理
            if (gameStarted && e.target.tagName !== 'BUTTON') {
                e.preventDefault();
                if (jumping) {
                    endJump();
                }
            }
        }, { passive: false });

        // 防止页面滚动和缩放
        document.addEventListener('touchmove', (e) => {
            if (gameStarted) {
                e.preventDefault();
            }
        }, { passive: false });
        
        // 游戏模式选择
        normalModeBtn.addEventListener('click', () => {
            normalModeBtn.classList.add('active');
            timeModeBtn.classList.remove('active');
            gameMode = 'normal';
        });
        
        timeModeBtn.addEventListener('click', () => {
            timeModeBtn.classList.add('active');
            normalModeBtn.classList.remove('active');
            gameMode = 'time';
        });
        
        // 开始游戏按钮
        startBtn.addEventListener('click', () => {
            startScreen.style.display = 'none';
            gameStarted = true;
            
            // 开始播放背景音乐
            if (soundEnabled) {
                bgMusic.play().catch(e => console.log("Background music failed to play:", e));
            }
            
            init();
            restartAnimation();
        });
        
        // 为开始按钮添加触摸事件
        startBtn.addEventListener('touchstart', (e) => {
            e.preventDefault();
            startScreen.style.display = 'none';
            gameStarted = true;
            
            // 开始播放背景音乐
            if (soundEnabled) {
                bgMusic.play().catch(e => console.log("Background music failed to play:", e));
            }
            
            init();
            restartAnimation();
        });
        
        // 返回主菜单按钮
        backToMainBtn.addEventListener('click', () => {
            gameOverElement.style.display = 'none';
            startScreen.style.display = 'block';
            gameStarted = false;
            
            if (soundEnabled) {
                bgMusic.pause();
                bgMusic.currentTime = 0;
            }
            
            stopAnimation();
        });
        
        // 为返回主菜单按钮添加触摸事件
        backToMainBtn.addEventListener('touchstart', (e) => {
            e.preventDefault();
            gameOverElement.style.display = 'none';
            startScreen.style.display = 'block';
            gameStarted = false;
            
            if (soundEnabled) {
                bgMusic.pause();
                bgMusic.currentTime = 0;
            }
            
            stopAnimation();
        });
        
        // 重新开始按钮
        restartBtn.addEventListener('click', () => {
            gameOverElement.style.display = 'none';
            stopAnimation();
            init();
            restartAnimation();
        });
        
        // 为重新开始按钮添加触摸事件
        restartBtn.addEventListener('touchstart', (e) => {
            e.preventDefault();
            gameOverElement.style.display = 'none';
            stopAnimation();
            init();
            restartAnimation();
        });
        
        // 窗口大小调整
        window.addEventListener('resize', () => {
            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();
            renderer.setSize(window.innerWidth, window.innerHeight);
        });
        
        // 音频控制图标切换
        function updateAudioIcon() {
            if (soundEnabled) {
                audioIcon.innerHTML = '<path d="M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z"/>';
            } else {
                audioIcon.innerHTML = '<path d="M16.5 12c0-1.77-1.02-3.29-2.5-4.03v2.21l2.45 2.45c.03-.2.05-.41.05-.63zm2.5 0c0 .94-.2 1.82-.54 2.64l1.51 1.51C20.63 14.91 21 13.5 21 12c0-4.28-2.99-7.86-7-8.77v2.06c2.89.86 5 3.54 5 6.71zM4.27 3L3 4.27 7.73 9H3v6h4l5 5v-6.73l4.25 4.25c-.67.52-1.42.93-2.25 1.18v2.06c1.38-.31 2.63-.95 3.69-1.81L19.73 21 21 19.73l-9-9L4.27 3zM12 4L9.91 6.09 12 8.18V4z"/>';
            }
        }
        
        // 播放音效
        function playSound(sound) {
            if (soundEnabled) {
                sound.currentTime = 0;
                sound.play().catch(e => console.log("Audio play failed:", e));
            }
        }
        
        // 音频控制事件
        audioControl.addEventListener('click', () => {
            soundEnabled = !soundEnabled;
            updateAudioIcon();
            
            if (soundEnabled) {
                if (gameStarted && !gameOver) {
                    try {
                        if (bgMusic.paused) {
                            bgMusic.play().catch(e => console.log("Background music failed to play:", e));
                        }
                    } catch (e) {
                        console.log("Error playing background music:", e);
                    }
                }
            } else {
                try {
                    if (!bgMusic.paused) {
                        bgMusic.pause();
                    }
                } catch (e) {
                    console.log("Error pausing background music:", e);
                }
            }
        });
        
        // 更新音频图标初始状态
        updateAudioIcon();
        
        // 第一次加载
        init();
        animate();
        
        // 加载高分
        loadHighScore();

        // 添加右键取消蓄力
        document.addEventListener('contextmenu', (e) => {
            if (gameStarted) {
                e.preventDefault(); // 阻止默认右键菜单
                cancelJump();
            }
        });

        // 界面提示
        const jumpHelpText = document.createElement('div');
        jumpHelpText.style.position = 'absolute';
        jumpHelpText.style.bottom = '20px';
        jumpHelpText.style.left = '20px';
        jumpHelpText.style.color = '#333';
        jumpHelpText.style.backgroundColor = 'rgba(255, 255, 255, 0.7)';
        jumpHelpText.style.padding = '8px 12px';
        jumpHelpText.style.fontSize = '14px';
        jumpHelpText.style.borderRadius = '5px';
        jumpHelpText.style.display = 'none';
        jumpHelpText.textContent = 'ESC或右键点击可取消蓄力';
        document.body.appendChild(jumpHelpText);
    </script>
</body>
</html>
